package com.zeyu.framework.tools.docconvert;

import com.zeyu.framework.tools.docconvert.struct.DocFileInfo;
import com.zeyu.framework.utils.DateUtils;
import com.zeyu.framework.utils.FileUtils;
import com.zeyu.framework.utils.IdGen;
import com.zeyu.framework.utils.NetUtils;
import com.zeyu.framework.utils.PathUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.artofsolving.jodconverter.OfficeDocumentConverter;
import org.artofsolving.jodconverter.office.DefaultOfficeManagerConfiguration;
import org.artofsolving.jodconverter.office.OfficeManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.util.Date;

/**
 * office转换服务上下文
 * Created by zeyuphoenix on 2017/2/28.
 */
// @Component
public class OfficeConvertService {

    // ================================================================
    // Constants
    // ================================================================

    /**
     * logger
     */
    private static final Logger logger = LoggerFactory.getLogger(OfficeConvertService.class);

    // ================================================================
    // Fields
    // ================================================================

    // 端口和路径
    private String officePort;
    private String officeHome;

    // office 转换管理器
    private OfficeManager officeManager;
    private OfficeDocumentConverter documentConverter;

    // ================================================================
    // Constructors
    // ================================================================

    /**
     *
     * 创建一个新的实例 OfficeConService.
     */
    public OfficeConvertService() {
        this(null, null);
    }

    /**
     *
     * 创建一个新的实例 OfficeConService.
     * @param officePort 端口
     * @param officeHome 地址
     */
    public OfficeConvertService(String officePort, String officeHome) {
        try {
            this.officePort = officePort;
            this.officeHome = officeHome;

            DefaultOfficeManagerConfiguration configuration = new DefaultOfficeManagerConfiguration();

            //设置转换端口，默认为8100
            if (StringUtils.isNotBlank(this.officePort)) {
                configuration.setPortNumber(Integer.parseInt(this.officePort));
                logger.info("office转换服务监听端口设置为：" + this.officePort);
            }

            //设置office安装目录
            if (StringUtils.isNotBlank(this.officeHome)) {
                configuration.setOfficeHome(new File(this.officeHome));
                logger.info("设置office安装目录为：" + this.officeHome);
            }

            boolean available = NetUtils.isPortAvailable(Integer.valueOf(this.officePort));
            if (!available) {
                logger.warn("port {} is usage, please check libreoffice service is started or not, if other service " +
                        "use this port, please change port in application.properties.", this.officePort);
                return;
            }

            officeManager = configuration.buildOfficeManager();
            documentConverter = new OfficeDocumentConverter(officeManager);
        } catch (Exception e) {
            logger.error("初始化转换器失败,请检查libreoffice安装信息", e);
        }
    }

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    // ================================================================
    // Public or Protected Methods
    // ================================================================

    protected void init() {
        try {
            officeManager.start();
        } catch (Exception e) {
            logger.error("init error", e);
        }
    }

    protected void destroy() {
        try {
            officeManager.stop();
        } catch (Exception e) {
            logger.error("destroy error", e);
        }
    }

    public String getOfficePort() {
        return officePort;
    }

    public void setOfficePort(String officePort) {
        this.officePort = officePort;
    }

    public String getOfficeHome() {
        return officeHome;
    }

    public void setOfficeHome(String officeHome) {
        this.officeHome = officeHome;
    }

    public OfficeManager getOfficeManager() {
        return officeManager;
    }

    public OfficeDocumentConverter getDocumentConverter() {
        return documentConverter;
    }

    /**
     * 转换上传文件为doc file info
     */
    public DocFileInfo transDocFileInfo(MultipartFile file) throws Exception {
        DocFileInfo fileInfo = new DocFileInfo();

        String folderAndName = getFileUriGeneratedPart(file.getOriginalFilename(), IdGen.uuid());
        String path = PathUtils.getWebRoot() + FileConvertHandler.UPLOAD_PATH + File.separator + folderAndName;

        File realFile = new File(path);
        if (!realFile.getParentFile().exists()) {
            if (!realFile.getParentFile().mkdirs()) {
                throw new Exception("创建文件上传目录失败");
            }
        }
        fileInfo.setName(FilenameUtils.getBaseName(new String(file.getOriginalFilename().getBytes("ISO-8859-1"), "UTF-8")));
        fileInfo.setPath(FileConvertHandler.UPLOAD_PATH + File.separator + folderAndName);
        fileInfo.setExt(FilenameUtils.getExtension(file.getOriginalFilename()));

        //如果为pdf文件，设置pdf路径，后面也不用转换pdf了
        if (FileConvertHandler.FILETYPE_PDF.equalsIgnoreCase(FilenameUtils.getExtension(file.getOriginalFilename()))) {
            fileInfo.setPdfPath(FileConvertHandler.UPLOAD_PATH + File.separator + folderAndName);
        }
        fileInfo.setHash(DigestUtils.md5Hex(file.getInputStream()));
        fileInfo.setSize(file.getSize());
        fileInfo.setConState(0);
        fileInfo.setCreateTime(new Date());

        //转存文件
        file.transferTo(realFile);

        return fileInfo;
    }

    public DocFileInfo transDocFileInfo(File file) throws Exception {
        DocFileInfo fileInfo = new DocFileInfo();

        // 保留原始文件,生成新的睡觉文件
        String folderAndName = getFileUriGeneratedPart(file.getName(), IdGen.uuid());
        String path = PathUtils.getWebRoot() + FileConvertHandler.UPLOAD_PATH + File.separator + folderAndName;

        File realFile = new File(path);
        if (!realFile.getParentFile().exists()) {
            if (!realFile.getParentFile().mkdirs()) {
                throw new Exception("创建文件上传目录失败");
            }
        }
        fileInfo.setName(FilenameUtils.getBaseName(new String(file.getName().getBytes("ISO-8859-1"), "UTF-8")));
        fileInfo.setPath(FileConvertHandler.UPLOAD_PATH + File.separator + folderAndName);
        fileInfo.setExt(FilenameUtils.getExtension(file.getName()));

        // 如果为pdf文件，设置pdf路径，后面也不用转换pdf了
        if (FileConvertHandler.FILETYPE_PDF.equalsIgnoreCase(FilenameUtils.getExtension(file.getName()))) {
            fileInfo.setPdfPath(FileConvertHandler.UPLOAD_PATH + File.separator + folderAndName);
        }
        fileInfo.setHash(DigestUtils.md5Hex(new FileInputStream(file)));

        fileInfo.setSize(FileUtils.sizeOf(file));
        fileInfo.setConState(0);
        fileInfo.setCreateTime(new Date());

        // 复制到新路径
        FileUtils.copyFile(file, realFile);

        return fileInfo;
    }

    // ================================================================
    // Getter & Setter
    // ================================================================

    // ================================================================
    // Private Methods
    // ================================================================

    /**
     * 获取文件上传的随机路径(包括文件名)
     */
    public static String getFileUriGeneratedPart(String originalFilename, String fileName) {
        return "/" + DateUtils.getDate("yyyyMMdd") + "/" + FilenameUtils.getExtension(originalFilename) + "/" + fileName.toLowerCase() + "/" + fileName.toLowerCase() + "." + FilenameUtils.getExtension(originalFilename);
    }

    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    // ================================================================
    // Test Methods
    // ================================================================

}
